#ifndef __NIX_MUTEX_H__
#define __NIX_MUTEX_H__

#include <pthread.h>

#include "../non_copyable.h"
#include "../exceptions.h"

#include <memory>

namespace Boss
{

  BOSS_DECLARE_RUNTIME_EXCEPTION(Mutex)

  namespace Internal
  {

    class MutexImpl
      : private NonCopyable
    {
    public:
      MutexImpl()
        : MutexAttr(new pthread_mutexattr_t)
        , MutexHandle(new pthread_mutex_t)
      {
        if (pthread_mutexattr_settype(MutexAttr.get(), PTHREAD_MUTEX_RECURSIVE_NP) ||
          pthread_mutex_init(MutexHandle.get(), MutexAttr.get()))
        {
          throw MutexException("Can't create mutex");
        }
        if (pthread_mutexattr_destroy(MutexAttr.get()))
        {
          pthread_mutex_destroy(MutexHandle.get());
          throw MutexException("Can't create mutex");
        }
      }
      ~MutexImpl()
      {
        pthread_mutex_destroy(MutexHandle.get());
      }
      void Lock()
      {
        if (pthread_mutex_lock(MutexHandle.get()))
          throw MutexException("Can't lock mutex");
      }
      void UnLock()
      {
        if (pthread_mutex_unlock(MutexHandle.get()))
          throw MutexException("Can't unlock mutex");
      }

    private:
      std::auto_ptr<pthread_mutexattr_t> MutexAttr;
      std::auto_ptr<pthread_mutex_t> MutexHandle;
    };

  }

  typedef Internal::MutexImpl Mutex;

}

#endif  // !__NIX_MUTEX_H__
